﻿using System.Diagnostics;
using System.Text;

namespace DimensionsHelper.LanguageService.Syntax;

public enum SyntaxCommentKinds
{
    /// <summary>
    ///     行注释
    /// </summary>
    LineComment,

    /// <summary>
    ///     块注释
    /// </summary>
    BlockComment
}


/// <summary>
///     表示语法注释中的一行，如果注释是单行注释，此内容和所在的注释内容是相同的。
/// </summary>
[DebuggerDisplay("{Text,nq}")]
public sealed class SyntaxCommentLine : AbstractTextRange
{
    private SyntaxCommentLine(int start, int length, int startLine, string text)
    {
        Start = start;
        Width = length;
        Text = text;
        UpdateLine(startLine, startLine);
    }


    public override bool IsComment => true;


    public static SyntaxCommentLine Create(int start, int length, int startLine, string text)
    {
        return new SyntaxCommentLine(start, length, startLine, text);
    }
}


/// <summary>
///     源代码注释，包括行注释和块注释。
/// </summary>
[DebuggerDisplay("{Text,nq}")]
public sealed class SyntaxComment : AbstractTextRange
{
    internal readonly SyntaxList<SyntaxCommentLine> Lines;

    internal SyntaxComment(SyntaxCommentKinds kind, int start)
    {
        CommentKind = kind;
        Start = start;
        Lines = new SyntaxList<SyntaxCommentLine>();
    }


    /// <summary>
    ///     如果当前列表不是空，返回<see langword="true" />。
    /// </summary>
    public override bool IsEmpty => Lines.Count > 0;


    public override bool IsComment => true;


    /// <summary>
    ///     当前注释前跳过的换行符个数。
    /// </summary>
    public int LeadingEmptyLines { get; internal set; }


    /// <summary>
    ///     如果注释是C语言风格的，将此属性设置为<see langword="true" />。
    /// </summary>
    public bool IsCStyleComment { get; internal set; }


    /// <summary>
    ///     如果注释是行注释，返回<see langword="true" />
    /// </summary>
    public bool IsLineComment => CommentKind == SyntaxCommentKinds.LineComment;


    /// <summary>
    ///     如果注释是块注释，返回<see langword="true" />
    /// </summary>
    public bool IsBlockComment => CommentKind == SyntaxCommentKinds.BlockComment;


    /// <summary>
    ///     包含的行数
    /// </summary>
    public int Count => Lines.Count;


    /// <summary>
    ///     注释类型，分为多行和单行
    /// </summary>
    public SyntaxCommentKinds CommentKind { get; }


    /// <summary>
    ///     向列表末尾追加一个行注释并返回。
    /// </summary>
    /// <param name="start">行起始位置</param>
    /// <param name="length">行宽度</param>
    /// <param name="startLine">行号</param>
    /// <param name="line">行文本内容</param>
    /// <returns></returns>
    public void AddLine(int start, int length, int startLine, string line)
    {
        SyntaxCommentLine commentLine = SyntaxCommentLine.Create(start, length, startLine, line);
        AddLine(commentLine);
    }


    /// <summary>
    ///     添加一个已有的行注释节点
    /// </summary>
    private void AddLine(SyntaxCommentLine line)
    {
        // 更新 _start
        if (Lines.Count == 0)
        {
            Start = line.Start;
        }

        Lines.Add(line);
        Width = line.End - Start;
        // 更新 _text
        if (Lines.Count > 1)
        {
            Text += "\r\n";
        }

        Text += line.Text;
    }


    /// <summary>
    ///     将行注释的所有行添加到当前注释中。
    /// </summary>
    /// <param name="comment">已有的行注释</param>
    public void AddLines(SyntaxComment comment)
    {
        Debug.Assert(comment.IsLineComment);
        Lines.AddRange(comment.GetLines());
        Width = comment.End - Start;
    }


    /// <summary>
    ///     获取一个所有行的迭代器。
    /// </summary>
    public IEnumerable<SyntaxCommentLine> GetLines()
    {
        return Lines;
    }


    public void Update(int start, int length, string text)
    {
        Start = start;
        Width = length;
        Text = text;
    }

    public override string ToString()
    {
        return Text;
    }


    public string ToDisplayString(bool appendCommentSemantic)
    {
        StringBuilder sb = new();

        if (appendCommentSemantic && IsBlockComment)
        {
            sb.AppendLine("'!");
        }

        foreach (SyntaxCommentLine line in Lines)
        {
            if (appendCommentSemantic)
            {
                sb.Append(!IsBlockComment ? "' " : " !");
            }

            sb.AppendLine(line.Text);
        }

        if (appendCommentSemantic && IsBlockComment)
        {
            sb.AppendLine(" !'");
        }

        return sb.ToString();
    }
}


public static partial class NodeFactory
{
    public static SyntaxComment CreateLineComment(int start, int length, int startLine, string text)
    {
        SyntaxComment trivia = new(SyntaxCommentKinds.LineComment, start);
        trivia.AddLine(start, length, startLine, text);
        return trivia;
    }


    public static SyntaxComment CreateBlockComment(
        params (int Start, int Length, int StartLine, string Text)[] lines)
    {
        Debug.Assert(lines.Length > 0);
        SyntaxComment trivia = new(SyntaxCommentKinds.BlockComment, lines[0].Item1);
        foreach ((int start, int length, int startLine, string line) in lines)
        {
            trivia.AddLine(start, length, startLine, line);
        }

        return trivia;
    }
}